package com.jun.admin.core.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.jun.admin.core.model.excel.entity.NoModelWriteData;
import com.jun.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author yuejun.li
 * @date 2024/10/9 16:07:00
 * Excel的导出和导入工具类
 */
@Slf4j
public class ExcelUtil {

    /**
     * 默认大小 10M
     */
    private static final long DEFAULT_MAX_SIZE = 10 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    private static final int FILE_NAME_MAX = 100;

    /**
     * 默认的文件类型
     */
    private static final List<String> EXCEL_EXTENSIONS = Arrays.asList(".xls",".xlsx",".csv");

    /**
     * 简单导入（导入全部sheet）
     * @param file 文件
     * @param cls  类对象（空则为无对象导入）
     * @param listener 监听器
     */
    public static <T> void excelImport(MultipartFile file, Class<T> cls, ReadListener listener) throws IOException {
        //文件校验
        assertAllowed(file);

        InputStream inputStream = file.getInputStream();
        //默认自动关闭流（若想调整为手动关闭，则需要分布实现）
        if(cls == null){
            EasyExcel.read(inputStream, listener).doReadAll();
        }else{
            EasyExcel.read(inputStream, cls, listener).doReadAll();
        }
    }

    /**
     * 有对象简单导入（导入某页sheet）
     * @param file 文件
     * @param cls  类对象（空则为无对象导入）
     * @param listener 监听器
     */
    public static <T> void excelImport(MultipartFile file, Class<T> cls, ReadListener listener,int sheetNo) throws IOException {
        //文件校验
        assertAllowed(file);

        InputStream inputStream = file.getInputStream();
        //默认自动关闭流（若想调整为手动关闭，则需要分布实现）
        if(cls == null){
            EasyExcel.read(inputStream, listener).sheet(sheetNo).doRead();
        }else{
            EasyExcel.read(inputStream, cls, listener).sheet(sheetNo).doRead();
        }
    }

    /**
     * 有对象简单导出
     * @param response response对象
     * @param cls 类对象
     * @param fileName 文件名
     * @param records 数据集
     * @throws UnsupportedEncodingException
     */
    public static <T> void excelExport(HttpServletResponse response, Class<T> cls, String fileName,List<T> records) throws UnsupportedEncodingException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));

        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel
                    .write(response.getOutputStream(), cls)
                    .build();

            //导出
            excelWriter.write(records,EasyExcel.writerSheet(fileName).build());
        }catch (IOException e) {
            log.error("export excel error error list:{}", e);
        } finally {
            //一定要关掉
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    /**
     * 无对象简单导出
     * @param response response对象
     * @param data 数据集
     */
    public static <T> void noModelExcelExport(HttpServletResponse response, NoModelWriteData data) throws UnsupportedEncodingException {
        String fileName = data.getFileName();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));

        ExcelWriter excelWriter = null;
        try {
            //excel全局配置
            excelWriter = EasyExcel
                    .write(response.getOutputStream())
                    .head(head(data.getHeadMap()))
                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(data.getColumnWidth()))
                    .build();

            //一页sheet配置
            WriteSheet writeSheet = EasyExcel
                    .writerSheet(fileName)
                    .build();

            //导出
            excelWriter.write(dataList(data.getDataList(),data.getDataStrMap()),writeSheet);
        }catch (IOException e) {
            log.error("export excel error error list:{}", e);
        } finally {
            //一定要关掉
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    /**
     * 设置导出的数据内容
     */
    public static List<List<Object>> dataList(List<Map> dataList, String[] dataStrMap) {
        List<List<Object>> list = new ArrayList<List<Object>>();
        for (Map<String, Object> map : dataList) {
            List<Object> data = new ArrayList<Object>();
            for (int i = 0; i < dataStrMap.length; i++) {
                data.add(map.get(dataStrMap[i]));
            }
            list.add(data);
        }
        return list;
    }

    /**
     * 设置表头
     */
    public static List<List<String>> head(String[] headMap) {
        List<List<String>> list = new ArrayList<List<String>>();

        for (String head : headMap) {
            List<String> headList = new ArrayList<String>();
            headList.add(head);
            list.add(headList);
        }
        return list;
    }

    /**
     * 文件校验
     * @param file
     */
    public static void assertAllowed(MultipartFile file) {
        //文件是否为空
        if (file.isEmpty() || file.getSize() == 0) {
            throw new ServiceException("上传附件不能为空！");
        }

        //文件是否符合规范
        String filename = file.getOriginalFilename();
        if (filename != null) {
            int fileNamelength = file.getOriginalFilename().length();

            if (fileNamelength > FILE_NAME_MAX) {
                throw new ServiceException("文件名过长");
            }
        } else {
            throw new ServiceException("文件名不允许为空");
        }

        long size = file.getSize();
        if (size > DEFAULT_MAX_SIZE) {
            throw new ServiceException("文件过大");
        }

        String fileType = filename.substring(filename.lastIndexOf("."));
        if (!EXCEL_EXTENSIONS.contains(fileType)) {
            throw new ServiceException("上传附件的类型不为Excel文件！");
        }
    }
}
